﻿using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using WorldMapBase.Collision;
using WorldMapBase.Display;
using WorldMapBase.Tile.Pool;
using WorldMapNew;
using Yoozoo.Libs;
using Yoozoo.Managers;
using static WorldMapBase.WorldMapConfigData;

namespace WorldMapBase.Tile
{
    /// <summary>
    /// 多元素地块
    /// </summary>
    public class MultiElementTile : IClass
    {
        /// <summary>
        /// 地块信息
        /// </summary>
        private WorldMapNew.MapChunckLayer m_TileData;

        private int m_TileSize;// 地块大小
        private int m_LodIndex;
        private int m_TileIndex;// 粒度坐标系下下标
        private int m_LayerIndex;// 层级下标 
        private int m_tileDataIdx;
        private int m_chunckId;
        private chunckInfoDta m_tileInfo;
        private Vector3 m_ChunckOffset = Vector3.zero;
        /// <summary>
        /// 地块物件
        /// </summary>
        private List<CommandTileElement> m_TileElements;

        private IDisplayCommandInterface m_DisplayCommandInterface;

        private Dictionary<int, int> m_debugTileElementNum;

        private Dictionary<int, bool> m_mapPointElements;// 出生点创建状态 -放置出生点单独调用重复创建

        public MultiElementTile()
        {
            m_TileElements = new List<CommandTileElement>(100);
            m_mapPointElements = new Dictionary<int, bool>();
        }
        
        /// <summary>
        /// 创建地块逻辑对像
        /// </summary>
        /// <param name="tile">地块数据</param>
        /// <returns></returns>
        public static MultiElementTile Create(int lodIndex,WorldMapNew.MapChunckLayer tileData, int tileSize,int tileIndex,int layerIdx,int chunckId,IDisplayCommandInterface displayCommandInterface)
        {
            MultiElementTile tileElement = ClassManager.Get<MultiElementTile>();
            tileElement.Initialize(lodIndex, tileData, tileSize, tileIndex, layerIdx, chunckId, displayCommandInterface);
            return tileElement;
        }
        
        public static void Free(MultiElementTile item)
        {
            ClassManager.Free(item);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="tileData">地块数据</param>
        void Initialize(int lodIndex, WorldMapNew.MapChunckLayer tileData, int tileSize,int tileIndex,int layerIdx,int chunckId, IDisplayCommandInterface displayCommandInterface)
        {
            m_TileData = tileData;
            m_TileSize = tileSize;
            m_LodIndex = lodIndex;
            m_TileIndex = tileIndex;
            m_LayerIndex = layerIdx;
            m_chunckId = chunckId;
            m_tileInfo = GetChunckInfoById(m_chunckId);
            m_tileDataIdx = 0;//WorldMapConfigData.GetMapChunckDataIdx(lodIndex, m_TileData.layerSize, tileIndex, m_tileInfo.rotation);
            m_ChunckOffset = WorldMapConfigData.GetMapChunckPos(m_TileData.layerID, lodIndex, m_LayerIndex);
            m_DisplayCommandInterface = displayCommandInterface;
            CreateTileElementPool();
            UpdateAlliancePointShow(true);
        }

        /// <summary>
        /// 创建物件逻辑对像
        /// </summary>
        public void CreateTileElementPool()
        {
            if (m_TileData.layerID == WorldEntry.MAP_POINT_ID && WorldEntry.bMapPointShow == false) return;// 出生点层级 判断
            var listInfo = m_TileData.elementDatas[m_tileDataIdx];
         
            int level = WorldMapConfigData.GetMapChunckLevel();
            for (int i = 0; i < listInfo.elementDatas.Count; i++)
            {
                TileElement tileElementData = listInfo.elementDatas[i];
                // 需要将data旋转一下
                tileElementData = WorldMapConfigData.GetTileElementByAngle(tileElementData, m_tileInfo);
                if (!GetMapPointShow(tileElementData, out int posIdx)) continue; // 判断出生点显示
                if(!GetMapElementLevel(tileElementData,level)) continue;// 判断性能等级
                if(GetMapElementHide(tileElementData,i)) continue;// 判断装饰物隐藏
                CheckMapPointResId(ref tileElementData);
                // 添加对象
                CommandTileElement tileElement = CommandTileElement.Create(m_LodIndex, m_TileData.layerID, tileElementData, m_ChunckOffset, m_DisplayCommandInterface);
                // 添加出生点创建记录
                if (m_TileData.layerID == WorldEntry.MAP_POINT_ID && posIdx > 0) m_mapPointElements[posIdx] = true;
                m_TileElements.Add(tileElement);
            }
        }

        /// <summary>
        /// 更新地图块中街区点表现
        /// </summary>
        /// <param name="bShow"></param>
        public void UpdateAlliancePointShow(bool bShow)
        {
            if (m_TileData.layerID != WorldEntry.PLANE_LAYER_ID || m_LodIndex > 2) return;// 地表层级 判断
            DynamicLayerMgr.worldEntry._alliancePointSystem.UpdateTileAlliancePoint(m_TileIndex, bShow);
        }

        // 对出生点资源id特殊处理
        private void CheckMapPointResId(ref TileElement tileElementData)
        {
            if (!(m_TileData.layerID == WorldEntry.MAP_POINT_ID && WorldEntry.bMapPointShow)) return;
            if (tileElementData.pointType > 0 && tileElementData.pointType != (int)WorldEntry.MapPointType.E_Alliance)
            {
                if (WorldEntry.GetMapPointCheck())
                {
                    tileElementData.resID = 2;
                }
                else
                {
                    tileElementData.resID = 1;
                }
            }
        }

        // 判断一个出生点显示
        private bool GetMapPointShow(TileElement elementData,out int posidx)
        {
            bool bShow = true;
            posidx = -1;
            if (m_TileData.layerID == WorldEntry.MAP_POINT_ID)// 出生点层级才需要判断
            {
                bShow = WorldEntry.bMapPointShow;// 显示状态
                bShow = bShow && WorldEntry.GetShowMapType(elementData.pointType);// 类型
             
                if (WorldEntry.bMapPointCheck) // 占领状态
                {
                    // 计算在10x10坐标系下idx
                    int pos_x0 = (int)((elementData.position.x + m_ChunckOffset.x) * 0.1f);
                    int pos_y0 = (int)((elementData.position.z + m_ChunckOffset.z) * 0.1f);
                    int lineNum = WorldEntry.m_mapSize / 10;
                    int idx = pos_x0 + pos_y0 * lineNum;
                    bShow = bShow && WorldEntry.GetAllianceChunck(idx);
                }
                if (bShow)
                {
                    int pos_x = (int)(elementData.position.x + WorldEntry.m_iTileSize * 0.5f);
                    int pos_y = (int)(elementData.position.z + WorldEntry.m_iTileSize * 0.5f);
                    posidx = pos_x + pos_y * WorldEntry.m_iTileSize;
                    bShow = WorldEntry.GetMapPointState(m_TileIndex, posidx) && !DynamicLayerMgr.worldEntry._mapPointAdornSystem.GetPointState2(m_TileIndex, posidx);
                  
                }
                if (bShow)
                {
                    // 判断路点类型 如果是普通出生点 需要判断裁切
                    if (elementData.pointType <= (int)WorldEntry.MapPointType.E_CityAndRes)
                    {
                        int idx = GetMapPointIdxByPos(elementData.position.x + m_ChunckOffset.x, elementData.position.z + m_ChunckOffset.z);
                        bShow = !WorldMapConfigData.GetMapPointHide(idx);
                    }
                }
            }
            return bShow;
        }

        // 判断一个对象性能等级
        private bool GetMapElementHide(TileElement tileElementData, int itemIdx)
        {
            bool hide = false;
            if (m_TileData.layerID == WorldEntry.TREE_LAYER_ID)
            {
                hide = WorldMapConfigData.GetElementShow(m_LayerIndex, itemIdx);
            }
            return hide;
        }

        // 判断一个对象性能等级
        private bool GetMapElementLevel(TileElement tileElementData, int level)
        {
            bool bShow = true;
            bShow = (tileElementData.level <= level);// 判断地图块元素 性能等级 
            if (WorldMapConfigData.GetMapDebug() && bShow)
            {
                int resType = WorldMapConfigData.GetMapChunckEntityTypeByResId(tileElementData.resID);
                bShow = GetTileDebugElementNum(resType);
            }
            int layerID = m_TileData.layerID;
            if (layerID == WorldEntry.MOUNTAINRANGE_LAYER_ID || layerID == WorldEntry.PLANE_LAYER_ID || layerID == WorldEntry.MAP_POINT_ID)
            {
                bShow = bShow || true;// 特殊层级 一直显示 
            }
            return bShow;
        }
        public bool GetTileDebugElementNum(int type)
        {
            bool bCanAdd = true;
            if (m_debugTileElementNum == null) m_debugTileElementNum = new Dictionary<int, int>();
            m_debugTileElementNum.TryGetValue(type,out int num);
            int maxNum = WorldMapConfigData.GetMapDebugChunckEntityNum(type);
            if (maxNum >= 0)
            {
                if (num >= maxNum)
                {
                    bCanAdd = false;
                }
                else
                {
                    num++;
                    m_debugTileElementNum[type] = num;
                }
            }
            else
            {
                num++;
                m_debugTileElementNum[type] = num;
            }
            return bCanAdd;
        }

        public void CreateTilePoint(int posIdx)
        {
            bool bExist = false;
            m_mapPointElements.TryGetValue(posIdx, out bExist);
            if (bExist) return;// 已存在删除
            // 解析该idx对应地图坐标 
            int idx_x = posIdx % m_TileSize;
            int idx_y = posIdx / m_TileSize;
            var listInfo = m_TileData.elementDatas[m_tileDataIdx].elementDatas;

            for (int i = 0; i < listInfo.Count; i++)
            {
                var tileElementData = listInfo[i];
                // 需要将data旋转一下
                tileElementData = WorldMapConfigData.GetTileElementByAngle(tileElementData, m_tileInfo);
                // 判断出生点添加
                int pos_x = (int)(tileElementData.position.x + m_TileSize * 0.5f);
                int pos_y = (int)(tileElementData.position.z + m_TileSize * 0.5f);
                bool bPointShow = GetMapPointShow(tileElementData, out int posIdx1);
                if (idx_x == pos_x && idx_y == pos_y && bPointShow)
                {
                    // 添加对象
                    CheckMapPointResId(ref tileElementData);
                    CommandTileElement tileElement = CommandTileElement.Create(m_LodIndex, m_TileData.layerID, tileElementData, m_ChunckOffset, m_DisplayCommandInterface);
                    m_TileElements.Add(tileElement);
                    m_mapPointElements[posIdx] = true;
                    return;
                }
            }
        }

        public void DestroyTilePoint(int posIdx)
        {
            bool bExist = true;
            m_mapPointElements.TryGetValue(posIdx, out bExist);
            if (!bExist) return;// 不存在
            // 解析该idx对应地图坐标 
            int idx_x = posIdx % m_TileSize;
            int idx_y = posIdx / m_TileSize;

            for (int i = 0; i < m_TileElements.Count; i++)
            {
                var tileElement = m_TileElements[i];

                // 判断出生点添加
                Vector3 localPos = tileElement.m_Data.position - m_ChunckOffset;
                int pos_x = (int)(localPos.x + m_TileSize * 0.5f);
                int pos_y = (int)(localPos.z + m_TileSize * 0.5f);
                if (idx_x == pos_x && idx_y == pos_y)
                {
                    // 删除对象
                    ClassPoolManager.RecoverCommandTileEle(tileElement);
                    m_TileElements.RemoveAt(i);
                    m_mapPointElements[posIdx] = false;
                    return;
                }
            }
        }

        public bool IsMapPointRender()
        {
            bool render = false;
            if (m_TileData.layerID == WorldEntry.MAP_POINT_ID)// 出生点层级判断
            {
                if (m_TileElements != null)
                {
                    var camera = WorldCameraManager.GetInstance("CameraManager");
                    List<Vector2> corners = new List<Vector2>();
                    Vector3 v30 = camera.m_CornersPosition[0];
                    corners.Add(new Vector2(v30.x, v30.z));
                    Vector3 v31 = camera.m_CornersPosition[1];
                    corners.Add(new Vector2(v31.x, v31.z));
                    Vector3 v32 = camera.m_CornersPosition[3];
                    corners.Add(new Vector2(v32.x, v32.z));
                    Vector3 v33 = camera.m_CornersPosition[2];
                    corners.Add(new Vector2(v33.x, v33.z));
                    for (int i = 0; i < m_TileElements.Count; i++)
                    {
                        render = m_TileElements[i].IsElementRender(corners);
                
                        if (render) break;
                    }
                }
            }
          
            return render;
        }

        /// <summary>
        /// 回收当前对像回调
        /// </summary>
        public void OnReset()
        {
            DestroyTileElementPool();
            UpdateAlliancePointShow(false);
            m_TileData = null;
            if(m_debugTileElementNum != null) m_debugTileElementNum.Clear();
        }

        /// <summary>
        /// 删除当前地块物件
        /// </summary>
        public void DestroyTileElementPool()
        {
            if (m_TileElements != null)
            {
                for (int i = 0, cnt = m_TileElements.Count; i < cnt; i++)
                {
                    ClassPoolManager.RecoverCommandTileEle(m_TileElements[i]);
                }
                m_TileElements.Clear();
            }
            m_mapPointElements.Clear();
        }

        public void ResetQuality()
        {
            DestroyTileElementPool();
            CreateTileElementPool();
        }

        public int GetMapPointIdxByPos(float x,float y)
        {
            int pointIdx = -1;
            int int_x = (int)x;
            int int_y = (int)y;
            int tileSize = WorldEntry.m_iTileSize;
            int tileX = int_x / tileSize;
            int tileY = int_y / tileSize;
            int tileLineNum = WorldEntry.m_mapLandSize / tileSize;
            int tileIdx = tileX + tileY * tileLineNum;
            int posIdx = int_x - tileX * tileSize + (int_y - tileY * tileSize) * tileSize;
            pointIdx = tileIdx * 1000 + posIdx;
            return pointIdx;
        }

    }
}
